import type {
  TDate,
  IDateRule,
  TToastIcon,
  TToastPosition,
  TVoidFn,
  TStrOrNum,
  TSwitchType,
  AnyObject,
  ILoading,
  IGetList,
  IGetListOptions
} from '@/common/types'
import useUserStore from '@/store/user'
import useSystemStore from '@/store/system'
import { getPay } from '@/common/api'

// 格式化时间
export function dateFormat(date:TDate = new Date(), fmt:string = 'YYYY-MM-DD'):string {
  if (typeof date === 'string') date = date.replace(/-/g, '/')
  const time:Date = new Date(date)
  const weekArr:string[] = ['日', '一', '二', '三', '四', '五', '六']
  const o:IDateRule = {
    'M+': time.getMonth() + 1, // 月份
    'D+': time.getDate(), // 日
    'h+': time.getHours(), // 小时
    'm+': time.getMinutes(), // 分
    's+': time.getSeconds(), // 秒
    'q+': Math.floor((time.getMonth() + 3) / 3), // 季度
    S: time.getMilliseconds(), // 毫秒
    W: time.getDay() // 星期
  }
  if (/(Y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, String(time.getFullYear()).substr(4 - RegExp.$1.length))
  }
  for (const k in o) {
    // @ts-ignore
    const val = o[k]
    if (new RegExp('(' + k + ')').test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1 === 'W'
          ? weekArr[val]
          : RegExp.$1.length === 1
            ? val
            : ('00' + val).substr(String(val).length)
      )
    }
  }
  return fmt
}

// toast弹窗
export function toast(title:string, fn?:TVoidFn, duration:number = 1500, mask:boolean = false, icon:TToastIcon = 'none', position:TToastPosition = 'bottom'):void {
  uni.showToast({
    title,
    icon,
    duration,
    position,
    mask,
    success: (res):void => {
      setTimeout(():void => {
        fn && fn()
      }, duration)
    }
  })
}

// loading弹窗
export function loading(title:string = '加载中...', fn?:TVoidFn, mask:boolean = true):ILoading {
  uni.showLoading({
    title,
    mask,
    success: ():void => {
      fn && fn()
    }
  })
  return {
    hide: ():void => {
      uni.hideLoading()
    }
  }
}

// 权限验证跳转
export function jump(url?:TStrOrNum, type:TSwitchType = 'navigateTo'):void {
  if (url === 'home') {
    uni.reLaunch({
      url: '/pages/index/index'
    })
    return
  }
  // 跳转
  if (url && typeof url === 'string') {
    switch (type) {
      case 'navigateTo':
        uni.navigateTo({ url })
        break
      case 'redirectTo':
        uni.redirectTo({ url })
        break
      case 'reLaunch':
        uni.reLaunch({ url })
        break
      case 'switchTab':
        uni.switchTab({ url })
        break
    }
  } else if (url && url as number > 0) {
    uni.navigateBack({ delta: url as number })
  } else {
    const pages = getCurrentPages()
    if (pages.length === 1) jump('home')
    else jump(1)
  }
}

// 获取元素数据
export function getElementInfo(select:string, that?:any):Promise<AnyObject> {
  return new Promise(resolve => {
    let element
    if (select.includes('.')) {
      element = that ? uni.createSelectorQuery().in(that).selectAll(select) : uni.createSelectorQuery().selectAll(select)
    } else {
      element = that ? uni.createSelectorQuery().in(that).select(select) : uni.createSelectorQuery().select(select)
    }
    element.boundingClientRect(res => {
      resolve(res)
    }).exec()
  })
}

// 下载文件
export function downloadFile(url:string):Promise<unknown> {
  return new Promise(resolve => {
    uni.downloadFile({
      url,
      success: (res):void => {
        if (res.statusCode === 200) {
          resolve(res.tempFilePath)
        }
      },
      fail: (err):void => {
        resolve(new Error(err))
      }
    })
  })
}

// 保存文件
export function saveFile(tempFilePath:string):void {
  uni.saveFile({
    tempFilePath,
    success(res) {
      toast('下载成功，文件保存在' + res.savedFilePath)
    }
  })
}

// 查看图片
export function viewImage(current:number, urls:Array<string>, showmenu:boolean = true):void {
  uni.previewImage({
    current,
    urls,
    showmenu
  })
}

// 复制数据
export function copyData<T extends object>(data:T):T {
  return data ? JSON.parse(JSON.stringify(data)) : null
}

// 获取rpx转px值 默认底部悬浮按钮高度
export function px(num:number = 134):number {
  return uni.upx2px(num)
}

// 拨打电话
export function callPhone(phoneNumber:string):void {
  uni.makePhoneCall({
    phoneNumber
  })
}

// 获取列表
export class GetList<T extends AnyObject, K> implements IGetList<T, K> {
  public _has_more:boolean = true
  public total:number = 0

  // eslint-disable-next-line no-useless-constructor
  constructor(
      public api: any,
      public params: T = {} as T,
      public options: IGetListOptions<K> = {
        pageSize: 10,
        page: 1,
        showLoading: false
      }
  ) {

  }

  async getList(): Promise<AnyObject[]> {
    const { pageSize, page, showLoading, initData } = this.options
    let load
    if (showLoading) load = loading()

    const res = await this.api(Object.assign({
      page: page,
      pagesize: pageSize
    }, this.params))
    uni.stopPullDownRefresh()
    load && load.hide()
    const data = res.data || []
    const list: AnyObject[] = (initData && initData(data)) ?? data
    if (list.length < pageSize) this._has_more = false
    return list
  }

  async nextPage(): Promise<AnyObject[]> {
    if (this._has_more) {
      this.options.page++
      return await this.getList()
    }
    return []
  }

  async reload(): Promise<AnyObject[]> {
    this.options.page = 1
    this._has_more = true
    return await this.getList()
  }

  async clear(): Promise<AnyObject[]> {
    return this.reload()
  }
}

// 防抖
export function debounce(fn:()=>void, interval:number = 1000) {
  let timer: number | null
  return () => {
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    timer = setTimeout(() => {
      fn && fn()
    }, interval)
  }
}

// 从剪贴板获取
export function getClipboard():Promise<AnyObject> {
  return new Promise(resolve => {
    uni.getClipboardData({
      complete: res => {
        uni.hideToast()
        resolve(res)
      }
    })
  })
}

// 复制到剪贴板
export function setClipboard(data:string, showToast = true):Promise<unknown> {
  return new Promise(resolve => {
    uni.setClipboardData({
      data,
      showToast,
      complete: (res):void => {
        if (!showToast) uni.hideToast()
        resolve(res)
      }
    })
  })
}

// 获取登录code
type provider = 'sinaweibo' | 'weixin' | 'qq' | 'xiaomi' | 'apple' | 'univerify'
export function getCode():Promise<string> {
  return new Promise(resolve => {
    uni.getProvider({
      service: 'oauth',
      success: result => {
        const providers = result.provider
        const provider = providers[0]

        uni.login({
          provider: provider as provider,
          success: res => {
            const { code } = res
            console.log(code)
            resolve(code)
          }
        })
      }
    })
  })
}

// 支付
export async function pay(item: AnyObject):Promise<string> {
  const { type, id, album_id } = item
  const params: AnyObject = { type, id }
  if (album_id) params.album_id = album_id
  const systemStore = useSystemStore()
  if (systemStore.systemInfo.osName === 'ios') return await payByIos(params)
  else return await payByAndroid(params)
}

// 苹果支付
async function payByIos(params: AnyObject):Promise<string> {
  // const res = await iosMpPay(params)
  return new Promise((resolve, reject) => {
    // resolve('success')
    reject(500)
  })
}

// 安卓支付
async function payByAndroid(params: AnyObject):Promise<string> {
  const res = await getPay(params)
  const { byteAuthorization, skuList } = res.data
  return new Promise((resolve, reject) => {
    const canUseRequestOrder = uni.canIUse('requestOrder')
    if (canUseRequestOrder) {
      tt.requestOrder({
        data: skuList,
        byteAuthorization,
        complete: (res: AnyObject) => {
          const { orderId } = res
          console.log(res)
          if (orderId) {
            tt.getOrderPayment({
              orderId,
              complete: (resp: AnyObject) => {
                console.log(resp)
                if (resp.errMsg === 'getOrderPayment:ok') resolve(resp.orderId)
                else reject(resp.errNo)
              }
            })
          } else {
            reject(500)
          }
        }
      })
    } else {
      reject(404)
    }
  })
}
